﻿using CustomCharacter.VoiceChat;
using Mirror;
using PlayerRoles.PlayableScps;
using PlayerRoles.Voice;
using System.Collections.Generic;
using System.Linq;
using VoiceChat.Networking;
using VoiceChat;
using Exiled.API.Features.Pools;
using Exiled.API.Features;
using HarmonyLib;

namespace CustomCharacter.Patches
{
    [HarmonyPatch(typeof(VoiceTransceiver),nameof(VoiceTransceiver.ServerReceiveMessage))]
    public static class ServerReceiveMessagePatch
    {
        [HarmonyPrefix]
        public static bool Prefix(NetworkConnection conn, VoiceMessage msg)
        {
            if (msg.SpeakerNull || msg.Speaker.netId != conn.identity.netId)
            {
                return false;
            }
            IVoiceRole senderRole = msg.Speaker.roleManager.CurrentRole as IVoiceRole;
            StandardVoiceModule voiceModule = senderRole.VoiceModule as StandardVoiceModule;
            if (!voiceModule.CheckRateLimit() || VoiceChatMutes.IsMuted(msg.Speaker, false))
            {
                return false;
            }
            Player speaker = Player.Get(msg.Speaker);
            var custom_sender = speaker.VC_GetCustomSender();
            var custom_listener = speaker.VC_GetCustomListener();
            List<Player> whitelist = ListPool<Player>.Pool.Get();
            var custom_msg = msg;
            custom_msg.Channel = VoiceChatChannel.RoundSummary;
            foreach (var sender in custom_sender)
            {
                foreach (var listener in sender.Listener)
                {
                    if (listener == speaker || whitelist.Contains(listener))
                        continue;

                    listener.ReferenceHub.connectionToClient.Send(custom_msg);
                    whitelist.Add(listener);
                }
            }
            if (custom_sender.Any(x => x.PrimaryCovery))
            {
                ListPool<Player>.Pool.Return(whitelist);
                return false;
            }
            VoiceChatChannel verified;
            if (VoiceChatManager.PrimaryChannelModifier.TryGetValue(speaker, out var modifier))
            {
                msg.Channel = modifier;
                verified = modifier;
            }
            else
                verified = voiceModule.ValidateSend(msg.Channel);
            if (verified == VoiceChatChannel.None)
                return false;
            voiceModule.CurrentChannel = verified;
            //验证通过
            List<VoiceChatChannel> channels = ListPool<VoiceChatChannel>.Pool.Get();
            channels.Add(verified);
            if (VoiceChatManager.ChannelSender.TryGetValue(speaker, out var pair))
            {
                foreach (var p in pair)
                {
                    VoiceChatChannel vali = p.Value ? voiceModule.ValidateSend(p.Key) : p.Key;
                    if (vali != VoiceChatChannel.None)
                        channels.Add(vali);
                }
            }
            foreach (Player receiver in Player.List)
            {
                if (receiver == null || (receiver == speaker && (verified != VoiceChatChannel.Mimicry || modifier == verified)) || whitelist.Contains(receiver))
                    continue;
                IVoiceRole receiverRole = receiver.ReferenceHub.roleManager.CurrentRole as IVoiceRole;
                VoiceChatChannel[] listener = receiver.VC_GetListener();
                foreach (var channel in channels)
                {
                    VoiceChatChannel receive_validated = receiverRole.VoiceModule.ValidateReceive(msg.Speaker, listener.Contains(channel) ?
                        receiverRole.VoiceModule.GetFriendlyChannel(channel) : channel);
                    if (receive_validated != VoiceChatChannel.None)
                    {
                        if (voiceModule is HumanVoiceModule && receive_validated == VoiceChatChannel.ScpChat && receiverRole.VoiceModule is StandardScpVoiceModule)
                            receive_validated = VoiceChatChannel.RoundSummary;
                        msg.Channel = receive_validated;
                        receiver.ReferenceHub.connectionToClient.Send(msg);
                        if (receive_validated != VoiceChatChannel.Proximity && receive_validated != VoiceChatChannel.Mimicry) //区域语音不冲突
                        {
                            break;
                        }
                    }
                }
            }
            ListPool<VoiceChatChannel>.Pool.Return(channels);
            ListPool<Player>.Pool.Return(whitelist);
            return false;
        }
    }
}
